/*
 * Copyright 2008 Zoundry LLC, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.zoundry.gaedt.core.models.application;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.zoundry.gaedt.core.ZGaeException;
import org.zoundry.gaedt.core.util.ZGaeEncrypter;
import org.zoundry.gaedt.core.util.ZGaeResourceUtil;
import org.zoundry.gaedt.core.util.ZGaeUTF8Util;
import org.zoundry.gaedt.core.util.ZGaeUtil;
import org.zoundry.gaedt.core.yaml.ZGaeYAMLModel;


/**
 * Models a single Google App Engine application. The model encapsulates several
 * different .yaml files, including app.yaml and .gae.yaml (the latter is a
 * tooling specific file that contains design time settings only, such as the
 * local port to use for testing).
 */
public class ZGaeApplicationModel
{
    private static final ZGaeEncrypter sPasswordEncrypter = new ZGaeEncrypter("Google App Engine | Application Model Password Encryption");

    /** The root location of the Google App Engine application. */
    private IContainer mApplicationRoot;

    /** The app's name. */
    private String mName = "";
    /** The app's runtime type. */
    private String mRuntimeType = "";
    /** The app's version. */
    private int mVersion = 1;
    /** The app's api version. */
    private int mApiVersion = 1;
    /** The default expiration of static files. */
    private String mDefaultExpiration = "";
    /** The handlers found in the app.yaml. */
    private List<IZGaeHandlerModel> mHandlers = new ArrayList<IZGaeHandlerModel>();

    /** The dev server port option. */
    private int mDevPort = 8080;
    /** The dev server address option. */
    private String mDevAddress = "";
    /** The dev server smtp host option. */
    private String mDevSMTPHost = "";
    /** The dev server smtp port option. */
    private int mDevSMTPPort = 25;
    /** The dev server smtp user option. */
    private String mDevSMTPUser = "";
    /** The dev server smtp password option. */
    private String mDevSMTPPassword = "";
    /** The dev server debug imports option. */
    private boolean mDevDebugImports;
    /** The dev server debug option. */
    private boolean mDevDebug;
    /** The dev server require indexes option. */
    private boolean mDevRequireIndexes;
    /** The dev server enable sendmail option. */
    private boolean mDevEnableSendmail;
    /** The dev server show mail body option. */
    private boolean mDevShowMailBody;
    /** The dev server auth domain option. */
    private String mDevAuthDomain = "";
    /** The dev server disable static caching option. */
    private boolean mDevDisableStaticCaching;

    /**
     * C'tor.
     *
     * @param aApplicationRoot
     */
    public ZGaeApplicationModel(IContainer aApplicationRoot)
    {
        setApplicationRoot(aApplicationRoot);
        load();
    }

    /**
     * Gets the application's name.
     */
    public String getName()
    {
        return mName;
    }

    /**
     * Sets the application name.
     *
     * @param aName
     */
    public void setName(String aName)
    {
        mName = aName;
    }

    /**
     * Gets the application's runtime type.
     */
    public String getRuntimeType()
    {
        return mRuntimeType;
    }

    /**
     * Sets the application's runtime type.
     *
     * @param aType
     */
    public void setRuntimeType(String aType)
    {
        mRuntimeType = aType;
    }

    /**
     * Gets the application's version number.
     */
    public int getVersion()
    {
        return mVersion;
    }

    /**
     * Sets the application's version number.
     *
     * @param aVersion
     */
    public void setVersion(int aVersion)
    {
        mVersion = aVersion;
    }

    /**
     * Gets the application's api version number.
     */
    public int getApiVersion()
    {
        return mApiVersion;
    }

    /**
     * Sets the application's api version number.
     *
     * @param aVersion
     */
    public void setApiVersion(int aVersion)
    {
        mApiVersion = aVersion;
    }

    /**
     * @return the defaultExpiration
     */
    public String getDefaultExpiration()
    {
        return mDefaultExpiration;
    }

    /**
     * @param aDefaultExpiration the defaultExpiration to set
     */
    public void setDefaultExpiration(String aDefaultExpiration)
    {
        mDefaultExpiration = aDefaultExpiration;
    }

    /**
     * Gets the application's handlers.
     */
    public List<IZGaeHandlerModel> getHandlers()
    {
        return mHandlers;
    }

    /**
     * Adds a handler to the list of handlers.
     *
     * @param aHandler
     */
    public void addHandler(IZGaeHandlerModel aHandler)
    {
        getHandlers().add(aHandler);
    }

    /**
     * Inserts the given handler into a specific location in the list
     * of handlers.
     *
     * @param aHandlerIndex
     * @param aHandler
     */
    public void insertHandler(int aHandlerIndex, IZGaeHandlerModel aHandler)
    {
        int handlerIdx = aHandlerIndex;

        if (handlerIdx < 0)
            handlerIdx = 0;
        if (handlerIdx > getHandlers().size())
            handlerIdx = getHandlers().size();

        getHandlers().add(handlerIdx, aHandler);
    }

    /**
     * Removes a handler at the given index.
     *
     * @param aHandlerIndex
     */
    public void removeHandler(int aHandlerIndex)
    {
        getHandlers().remove(aHandlerIndex);
    }

    /**
     * Removes a specific handler from the application model and
     * returns its relative location within the list of handlers.
     *
     * @param aHandler
     */
    public int removeHandler(IZGaeHandlerModel aHandler)
    {
        int idx = getHandlers().indexOf(aHandler);
        removeHandler(idx);
        return idx;
    }

    /**
     * Called to change the relative location of a handler within
     * the list of handlers.  The handler to move is passed in, along
     * with the number of spaces to move.  For example, to move the
     * handler 3 spaces earlier in the list, pass -3 for aMoveSpec.
     * To move a handler 1 space later in the list, pass 1 for aMoveSpec.
     *
     * @param aHandler
     * @param aMoveSpec
     */
    public int move(IZGaeHandlerModel aHandler, int aMoveSpec)
    {
        if (aMoveSpec == 0)
            return getHandlers().indexOf(aHandler);

        int oldIdx = removeHandler(aHandler);
        int newIdx = oldIdx + aMoveSpec;
        if (newIdx < 0)
            newIdx = 0;
        else if (newIdx > getHandlers().size())
            newIdx = getHandlers().size();
        getHandlers().add(newIdx, aHandler);
        return newIdx;
    }

    /**
     * Returns true if the given model is the first one in the list of
     * handlers.
     *
     * @param aModel
     */
    public boolean isFirstHandler(IZGaeHandlerModel aModel)
    {
        return getHandlers().size() > 0 && getHandlers().get(0) == aModel;
    }

    /**
     * Returns true if the given model is the last one in the list of
     * handlers.
     *
     * @param aModel
     */
    public boolean isLastHandler(IZGaeHandlerModel aModel)
    {
        return getHandlers().size() > 0 && getHandlers().get(getHandlers().size() - 1) == aModel;
    }

    /**
     * Gets the application's dev-time port number.
     */
    public int getDevPort()
    {
        return mDevPort;
    }

    /**
     * Sets the dev-time port.
     *
     * @param aPort
     */
    public void setDevPort(int aPort)
    {
        mDevPort = aPort;
    }

    /**
     * Gets the application's dev-time address.
     */
    public String getDevAddress()
    {
        return mDevAddress;
    }

    /**
     * Sets the application's dev-time address.
     *
     * @param aAddress
     */
    public void setDevAddress(String aAddress)
    {
        mDevAddress = aAddress;
    }

    /**
     * Gets the application's dev-time SMTP host.
     */
    public String getDevSMTPHost()
    {
        return mDevSMTPHost;
    }

    /**
     * Sets the application's dev-time SMTP host.
     *
     * @param aAddress
     */
    public void setDevSMTPHost(String aSMTPHost)
    {
        mDevSMTPHost = aSMTPHost;
    }

    /**
     * Gets the application's dev-time SMTP port.
     */
    public int getDevSMTPPort()
    {
        return mDevSMTPPort;
    }

    /**
     * Sets the dev-time SMTP port.
     *
     * @param aPort
     */
    public void setDevSMTPPort(int aPort)
    {
        mDevSMTPPort = aPort;
    }

    /**
     * Gets the application's dev-time SMTP username.
     */
    public String getDevSMTPUser()
    {
        return mDevSMTPUser;
    }

    /**
     * Sets the application's dev-time SMTP username.
     *
     * @param aAddress
     */
    public void setDevSMTPUser(String aUsername)
    {
        mDevSMTPUser = aUsername;
    }

    /**
     * Gets the application's dev-time SMTP password.
     */
    public String getDevSMTPPassword()
    {
        String encryptedPassword = mDevSMTPPassword;
        if (encryptedPassword == null)
            return "";
        String plaintextPassword = sPasswordEncrypter.decrypt(encryptedPassword);
        return plaintextPassword;
    }

    /**
     * Sets the application's dev-time SMTP username.
     *
     * @param aPlaintextPassword
     */
    public void setDevSMTPPassword(String aPlaintextPassword)
    {
        String encryptedPassword = null;
        if (aPlaintextPassword != null && !"".equals(aPlaintextPassword))
            encryptedPassword = sPasswordEncrypter.encrypt(aPlaintextPassword);
        mDevSMTPPassword = encryptedPassword;
    }

    /**
     * Returns the application's 'debug imports' setting.
     */
    public boolean isDevDebugImports()
    {
        return mDevDebugImports;
    }

    /**
     * Sets the application's 'debug imports' setting.
     *
     * @param aDebugImports
     */
    public void setDevDebugImports(boolean aDebugImports)
    {
        mDevDebugImports = aDebugImports;
    }

    /**
     * Gets the application's 'debug' option.
     */
    public boolean isDevDebug()
    {
        return mDevDebug;
    }

    /**
     * Sets the application's 'debug' option.
     *
     * @param aDebug
     */
    public void setDevDebug(boolean aDebug)
    {
        mDevDebug = aDebug;
    }

    /**
     * Gets the application's 'require indexes' option.
     */
    public boolean isDevRequireIndexes()
    {
        return mDevRequireIndexes;
    }

    /**
     * Sets the application's 'require indexes' option.
     *
     * @param aRequireIndexes
     */
    public void setDevRequireIndexes(boolean aRequireIndexes)
    {
        mDevRequireIndexes = aRequireIndexes;
    }

    /**
     * Returns the application's 'enable sendmail' option.
     */
    public boolean isDevEnableSendmail()
    {
        return mDevEnableSendmail;
    }

    /**
     * Sets the application's 'enable sendmail' dev-time option.
     *
     * @param aEnableSendmail
     */
    public void setDevEnableSendmail(boolean aEnableSendmail)
    {
        mDevEnableSendmail = aEnableSendmail;
    }

    /**
     * Returns the application's 'show mail body' flag.
     */
    public boolean isDevShowMailBody()
    {
        return mDevShowMailBody;
    }

    /**
     * Sets the application's 'show mail body' dev-time option.
     *
     * @param aShowMailBody
     */
    public void setDevShowMailBody(boolean aShowMailBody)
    {
        mDevShowMailBody = aShowMailBody;
    }

    /**
     * Returns the application's 'auth domain' option.
     */
    public String getDevAuthDomain()
    {
        return mDevAuthDomain;
    }

    /**
     * Sets the application's dev-time auth domain.
     *
     * @param aAuthDomain
     */
    public void setDevAuthDomain(String aAuthDomain)
    {
        mDevAuthDomain = aAuthDomain;
    }

    /**
     * Returns the application's 'disable static caching' option.
     */
    public boolean isDevDisableStaticCaching()
    {
        return mDevDisableStaticCaching;
    }

    /**
     * Sets the application's 'disable static caching' dev-time option.
     *
     * @param aDisableStaticCaching
     */
    public void setDevDisableStaticCaching(boolean aDisableStaticCaching)
    {
        mDevDisableStaticCaching = aDisableStaticCaching;
    }

    /**
     * Returns the app.yaml file location as an Eclipse {@link IFile}.
     */
    public IFile getAppYaml()
    {
        return (IFile) getChildResource("app.yml", "app.yaml");
    }

    /**
     * Returns the gae.yaml file location as an Eclipse {@link IFile}.
     */
    public IFile getGaeYaml()
    {
        return (IFile) getChildResource("gae.yml", "gae.yaml");
    }

    /**
     * Generic method to get a child resource of this application.  This method
     * will not return null - if none of the requested resource names correspond
     * to existing resources, the last one will be returned.
     *
     * @param aResourceName
     */
    protected IResource getChildResource(String ... aResourceName)
    {
        IFile file = null;
        for (String resourceName : aResourceName)
        {
            file = getApplicationRoot().getFile(new Path(resourceName));
            if (file.exists())
                return file;
        }
        return file;
    }

    /**
     * Loads the yaml information from any existing files.
     */
    protected void load()
    {
        IFile appYaml = getAppYaml();
        if (appYaml.exists())
        {
            String yamlData = loadYamlData(appYaml);
            ZGaeYAMLModel yamlModel = new ZGaeYAMLModel(yamlData);
            readAppYaml(yamlModel);
        }
        IFile gaeYaml = getGaeYaml();
        if (gaeYaml.exists())
        {
            String yamlData = loadYamlData(gaeYaml);
            ZGaeYAMLModel yamlModel = new ZGaeYAMLModel(yamlData);
            readGaeYaml(yamlModel);
        }
    }

    /**
     * Reads the YAML information in the app.yaml file.
     *
     * @param aYamlModel
     */
    protected void readAppYaml(ZGaeYAMLModel aYamlModel)
    {
        String appName = (String) aYamlModel.query("application");
        if (appName != null)
            setName(appName);
        String runtime = (String) aYamlModel.query("runtime");
        if (runtime != null)
            setRuntimeType(runtime);
        Number version = (Number) aYamlModel.query("version");
        if (version != null)
            setVersion(version.intValue());
        Number apiVersion = (Number) aYamlModel.query("api_version");
        if (apiVersion != null)
            setApiVersion(apiVersion.intValue());
        String defaultExpiration = (String) aYamlModel.query("default_expiration");
        if (defaultExpiration != null)
        {
            if (defaultExpiration.startsWith("\""))
                defaultExpiration = defaultExpiration.substring(1, defaultExpiration.length() - 1);
            setDefaultExpiration(defaultExpiration);
        }

        readHandlers(aYamlModel);
    }

    /**
     * Reads the handler information from the given YAML model.
     *
     * @param aYamlModel
     */
    protected void readHandlers(ZGaeYAMLModel aYamlModel)
    {
        List<Map<String, Object>> handlerList = (List) aYamlModel.query("handlers");
        for (Map<String, Object> handlerData : handlerList)
        {
            IZGaeHandlerModel handlerModel = ZGaeHandlerModelFactory.createHandler(handlerData);
            if (handlerModel != null)
                addHandler(handlerModel);
        }
    }

    /**
     * Reads the YAML information in the gae.yaml file.
     *
     * @param aYamlModel
     */
    protected void readGaeYaml(ZGaeYAMLModel aYamlModel)
    {
        String appName = (String) aYamlModel.query("application");
        if (appName != null)
            setName(appName);

        Number port = (Number) aYamlModel.query("port");
        if (port != null)
            setDevPort(port.intValue());
        String address = (String) aYamlModel.query("address");
        if (address != null)
            setDevAddress(address);
        String smtpHost = (String) aYamlModel.query("smtp_host");
        if (smtpHost != null)
            setDevSMTPHost(smtpHost);
        Number smtpPort = (Number) aYamlModel.query("smtp_port");
        if (smtpPort != null)
            setDevSMTPPort(smtpPort.intValue());
        String smtpUser = (String) aYamlModel.query("smtp_user");
        if (smtpUser != null)
            setDevSMTPUser(smtpUser);
        String smtpPassword = (String) aYamlModel.query("smtp_password");
        if (smtpPassword != null)
            setDevSMTPPassword(smtpPassword);
        Boolean debugImports = (Boolean) aYamlModel.query("debug_imports");
        if (debugImports != null)
            setDevDebugImports(debugImports);
        Boolean debug = (Boolean) aYamlModel.query("debug");
        if (debug != null)
            setDevDebug(debug);
        Boolean requireIndexes = (Boolean) aYamlModel.query("require_indexes");
        if (requireIndexes != null)
            setDevRequireIndexes(requireIndexes);
        Boolean enableSendmail = (Boolean) aYamlModel.query("enable_sendmail");
        if (enableSendmail != null)
            setDevEnableSendmail(enableSendmail);
        Boolean showMailBody = (Boolean) aYamlModel.query("show_mail_body");
        if (showMailBody != null)
            setDevShowMailBody(showMailBody);
        String authDomain = (String) aYamlModel.query("auth_domain");
        if (authDomain != null)
            setDevAuthDomain(authDomain);
        Boolean disableStaticCaching = (Boolean) aYamlModel.query("disable_static_caching");
        if (disableStaticCaching != null)
            setDevDisableStaticCaching(disableStaticCaching);
    }

    /**
     * Saves the contents of the model to disk.
     *
     * @throws ZGaeException
     */
    public void save() throws CoreException, ZGaeException
    {
        writeYamlToFile(toAppYamlModel(), getAppYaml());
        writeYamlToFile(toGaeYamlModel(), getGaeYaml());
    }

    /**
     * Serialize and return just the app.yaml data.
     */
    public String serializeAppYaml()
    {
        return toAppYamlModel().serialize();
    }

    /**
     * Serialize and return just the gae.yaml data.
     */
    public String serializeGaeYaml()
    {
        return toGaeYamlModel().serialize();
    }

    /**
     * Loads the Yaml data from the given file.
     *
     * @param aAppYaml
     */
    protected String loadYamlData(IFile aAppYaml)
    {
        try
        {
            return ZGaeResourceUtil.getContents(aAppYaml);
        }
        catch (ZGaeException e)
        {
            ZGaeUtil.logError(e);
            return "";
        }
    }

    /**
     * Writes YAML content to a .yaml file.
     *
     * @throws ZGaeException
     * @throws CoreException
     */
    private void writeYamlToFile(ZGaeYAMLModel aYamlModel, IFile aYamlFile) throws ZGaeException, CoreException
    {
        InputStream appYamlContent = getAsInputStream(aYamlModel);
        if (appYamlContent != null)
        {
            if (aYamlFile.exists())
            {
                aYamlFile.setContents(appYamlContent, true, true, null);
            }
            else
            {
                aYamlFile.create(appYamlContent, true, null);
            }
        }
    }

    /**
     * Gets the given yaml model as an input stream.
     *
     * @param aAppYamlModel
     * @throws ZGaeException
     */
    private InputStream getAsInputStream(ZGaeYAMLModel aAppYamlModel) throws ZGaeException
    {
        String yamlContent = aAppYamlModel.serialize();
        return ZGaeUTF8Util.getInputStream(yamlContent);
    }

    /**
     * @return the applicationRoot
     */
    public IContainer getApplicationRoot()
    {
        return mApplicationRoot;
    }

    /**
     * @param aApplicationRoot the applicationRoot to set
     */
    protected void setApplicationRoot(IContainer aApplicationRoot)
    {
        mApplicationRoot = aApplicationRoot;
    }

    /**
     * Gets the application model as a YAML model.  This returns just the information
     * that would be stored in the app.yaml file.
     */
    protected ZGaeYAMLModel toAppYamlModel()
    {
        final ZGaeYAMLModel yamlModel = new ZGaeYAMLModel();
        yamlModel.put("application", getName());
        yamlModel.put("runtime", getRuntimeType());
        yamlModel.put("version", getVersion());
        yamlModel.put("api_version", getApiVersion());
        String defaultExpiration = getDefaultExpiration();
        if (defaultExpiration != null && !"".equals(defaultExpiration.trim()))
            yamlModel.put("default_expiration", "\"" + defaultExpiration + "\"");

        final List<Map<String, Object>> handlerList = new ArrayList();
        IZGaeHandlerVisitor handlerSerializer = new IZGaeHandlerVisitor()
        {
            /**
             * @see org.zoundry.gaedt.core.models.application.IZGaeHandlerVisitor#visit(org.zoundry.gaedt.core.models.application.ZGaeScriptHandlerModel)
             */
            public void visit(ZGaeScriptHandlerModel aHandler)
            {
                Map<String, Object> handlerMap = new LinkedHashMap();
                handlerMap.put("url", aHandler.getUrl());
                handlerMap.put("script", aHandler.getScript());
                if (aHandler.getLogin() != TZGaeHandlerLoginType.None)
                    handlerMap.put("login", aHandler.getLogin().toString());

                handlerList.add(handlerMap);
            }

            /**
             * @see org.zoundry.gaedt.core.models.application.IZGaeHandlerVisitor#visit(org.zoundry.gaedt.core.models.application.ZGaeStaticDirectoryHandlerModel)
             */
            public void visit(ZGaeStaticDirectoryHandlerModel aHandler)
            {
                Map<String, Object> handlerMap = new LinkedHashMap();
                handlerMap.put("url", aHandler.getUrl());
                handlerMap.put("static_dir", aHandler.getStaticDir());
                if (aHandler.getLogin() != TZGaeHandlerLoginType.None)
                    handlerMap.put("login", aHandler.getLogin().toString());
                if (!ZGaeUtil.isNullOrEmpty(aHandler.getMimeType()))
                    handlerMap.put("mime_type", aHandler.getMimeType());
                if (!ZGaeUtil.isNullOrEmpty(aHandler.getExpiration()))
                    handlerMap.put("expiration", aHandler.getExpiration());

                handlerList.add(handlerMap);
            }

            /**
             * @see org.zoundry.gaedt.core.models.application.IZGaeHandlerVisitor#visit(org.zoundry.gaedt.core.models.application.ZGaeStaticFilePatternHandlerModel)
             */
            public void visit(ZGaeStaticFilePatternHandlerModel aHandler)
            {
                Map<String, Object> handlerMap = new LinkedHashMap();
                handlerMap.put("url", aHandler.getUrl());
                handlerMap.put("static_files", aHandler.getStaticFiles());
                if (aHandler.getLogin() != TZGaeHandlerLoginType.None)
                    handlerMap.put("login", aHandler.getLogin().toString());
                if (!ZGaeUtil.isNullOrEmpty(aHandler.getUpload()))
                    handlerMap.put("upload", aHandler.getUpload());
                if (!ZGaeUtil.isNullOrEmpty(aHandler.getMimeType()))
                    handlerMap.put("mime_type", aHandler.getMimeType());
                if (!ZGaeUtil.isNullOrEmpty(aHandler.getExpiration()))
                    handlerMap.put("expiration", aHandler.getExpiration());

                handlerList.add(handlerMap);
            }
        };
        for (IZGaeHandlerModel handlerModel : getHandlers())
            handlerModel.accept(handlerSerializer);
        yamlModel.put("handlers", handlerList);

        return yamlModel;
    }

    /**
     * Gets the application model as a YAML model.  This returns just the information
     * that would be stored in the gae.yaml file.
     */
    protected ZGaeYAMLModel toGaeYamlModel()
    {
        ZGaeYAMLModel yamlModel = new ZGaeYAMLModel();
        yamlModel.put("port", getDevPort());
        yamlModel.put("address", getDevAddress());
        yamlModel.put("smtp_host", getDevSMTPHost());
        yamlModel.put("smtp_port", getDevSMTPPort());
        yamlModel.put("smtp_user", getDevSMTPUser());
        yamlModel.put("smtp_password", getDevSMTPPassword());
        yamlModel.put("debug_imports", isDevDebugImports());
        yamlModel.put("debug", isDevDebug());
        yamlModel.put("require_indexes", isDevRequireIndexes());
        yamlModel.put("enable_sendmail", isDevEnableSendmail());
        yamlModel.put("show_mail_body", isDevShowMailBody());
        yamlModel.put("auth_domain", getDevAuthDomain());
        yamlModel.put("disable_static_caching", isDevDisableStaticCaching());

        return yamlModel;
    }
}
